/*      */ package com.zimbra.cs.mailbox.calendar;
/*      */ 
/*      */ import com.zimbra.common.calendar.ICalTimeZone;
/*      */ import com.zimbra.common.calendar.ParsedDateTime;
/*      */ import com.zimbra.common.calendar.TimeZoneMap;
/*      */ import com.zimbra.common.calendar.ZWeekDay;
/*      */ import com.zimbra.common.service.ServiceException;
/*      */ import com.zimbra.common.util.Log;
/*      */ import com.zimbra.common.util.ZimbraLog;
/*      */ import com.zimbra.cs.account.Provisioning;
/*      */ import com.zimbra.cs.account.Server;
/*      */ import com.zimbra.cs.util.Zimbra;
/*      */ import java.io.PrintStream;
/*      */ import java.text.ParseException;
/*      */ import java.util.ArrayList;
/*      */ import java.util.Calendar;
/*      */ import java.util.Collections;
/*      */ import java.util.Comparator;
/*      */ import java.util.Date;
/*      */ import java.util.Formatter;
/*      */ import java.util.GregorianCalendar;
/*      */ import java.util.HashSet;
/*      */ import java.util.Iterator;
/*      */ import java.util.LinkedList;
/*      */ import java.util.List;
/*      */ import java.util.Set;
/*      */ import org.apache.commons.httpclient.util.DateUtil;
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ public class ZRecur
/*      */   implements Cloneable
/*      */ {
/*      */   private static final long MAX_DATE_MILLIS = 221845392000000L;
/*      */   private static ExpansionLimits sExpansionLimits;
/*      */   
/*      */   public static enum Frequency
/*      */   {
/*   46 */     DAILY,  HOURLY,  MINUTELY,  MONTHLY,  SECONDLY,  WEEKLY,  YEARLY;
/*      */     
/*      */     private Frequency() {} }
/*      */   
/*      */   public static class ZWeekDayNum { public ZWeekDay mDay;
/*      */     public int mOrdinal;
/*      */     public ZWeekDayNum() {}
/*      */     
/*   54 */     public static class DayOnlyComparator implements Comparator<ZRecur.ZWeekDayNum> { public int compare(ZRecur.ZWeekDayNum lhs, ZRecur.ZWeekDayNum rhs) { return lhs.mDay.getCalendarDay() - rhs.mDay.getCalendarDay(); }
/*      */     }
/*      */     
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */     public ZWeekDayNum(int ord, ZWeekDay day)
/*      */     {
/*   63 */       this.mOrdinal = ord;this.mDay = day;
/*      */     }
/*      */     
/*      */     public String toString() {
/*   67 */       if (this.mOrdinal != 0) {
/*   68 */         return Integer.toString(this.mOrdinal) + this.mDay;
/*      */       }
/*   70 */       return this.mDay.toString();
/*      */     }
/*      */   }
/*      */   
/*      */   private static enum Tokens {
/*   75 */     BYDAY,  BYHOUR,  BYMINUTE,  BYMONTH,  BYMONTHDAY,  BYSECOND,  BYSETPOS,  BYWEEKNO, 
/*   76 */     BYYEARDAY,  COUNT,  FREQ,  INTERVAL,  UNTIL,  WKST;
/*      */     
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */     private Tokens() {}
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   static
/*      */   {
/*   93 */     sExpansionLimits = new ExpansionLimits(null);
/*      */     try {
/*   95 */       Server server = Provisioning.getInstance().getLocalServer();
/*      */       
/*   97 */       String val = server.getAttr("zimbraCalendarRecurrenceMaxInstances");
/*   98 */       sExpansionLimits.maxInstances = (val == null ? 0 : Integer.parseInt(val));
/*   99 */       val = server.getAttr("zimbraCalendarRecurrenceDailyMaxDays");
/*  100 */       sExpansionLimits.maxDays = (val == null ? 730 : Integer.parseInt(val));
/*  101 */       val = server.getAttr("zimbraCalendarRecurrenceWeeklyMaxWeeks");
/*  102 */       sExpansionLimits.maxWeeks = (val == null ? 520 : Integer.parseInt(val));
/*  103 */       val = server.getAttr("zimbraCalendarRecurrenceMonthlyMaxMonths");
/*  104 */       sExpansionLimits.maxMonths = (val == null ? 360 : Integer.parseInt(val));
/*  105 */       val = server.getAttr("zimbraCalendarRecurrenceYearlyMaxYears");
/*  106 */       sExpansionLimits.maxYears = (val == null ? 100 : Integer.parseInt(val));
/*  107 */       val = server.getAttr("zimbraCalendarRecurrenceOtherFrequencyMaxYears");
/*  108 */       sExpansionLimits.maxYearsOtherFreqs = (val == null ? 1 : Integer.parseInt(val));
/*      */     } catch (NumberFormatException e) {
/*  110 */       Zimbra.halt("Can't initialize recurrence expansion limits", e);
/*      */     } catch (ServiceException e) {
/*  112 */       Zimbra.halt("Can't initialize recurrence expansion limits", e);
/*      */     }
/*      */   }
/*      */   
/*      */   private Date estimateEndTimeByUntilAndHardLimits(ParsedDateTime dtStart) throws ServiceException {
/*  117 */     boolean forever = false;
/*  118 */     Calendar hardEnd = dtStart.getCalendarCopy();
/*  119 */     Frequency freq = this.mFreq;
/*  120 */     if (freq == null)
/*  121 */       freq = Frequency.WEEKLY;
/*  122 */     switch (freq) {
/*      */     case WEEKLY: 
/*  124 */       int weeks = sExpansionLimits.maxWeeks;
/*  125 */       if (weeks <= 0) {
/*  126 */         forever = true;
/*      */       } else
/*  128 */         hardEnd.add(3, weeks);
/*  129 */       break;
/*      */     case MONTHLY: 
/*  131 */       int months = sExpansionLimits.maxMonths;
/*  132 */       if (months <= 0) {
/*  133 */         forever = true;
/*      */       } else
/*  135 */         hardEnd.add(2, months);
/*  136 */       break;
/*      */     case YEARLY: 
/*  138 */       int years = sExpansionLimits.maxYears;
/*  139 */       if (years <= 0) {
/*  140 */         forever = true;
/*      */       } else
/*  142 */         hardEnd.add(1, years);
/*  143 */       break;
/*      */     case DAILY: 
/*  145 */       int days = sExpansionLimits.maxDays;
/*  146 */       if (days <= 0) {
/*  147 */         forever = true;
/*      */       } else
/*  149 */         hardEnd.add(6, days);
/*  150 */       break;
/*      */     default: 
/*  152 */       int otherFreqYears = Math.max(sExpansionLimits.maxYearsOtherFreqs, 1);
/*  153 */       hardEnd.add(1, otherFreqYears); }
/*      */     Date d;
/*      */     Date d;
/*  156 */     if (forever) {
/*  157 */       d = new Date(221845392000000L);
/*      */     } else
/*  159 */       d = hardEnd.getTime();
/*  160 */     if (this.mUntil != null) {
/*  161 */       Date until = this.mUntil.getDateForRecurUntil(dtStart.getTimeZone());
/*  162 */       if (until.before(d))
/*  163 */         d = until;
/*      */     }
/*  165 */     return d;
/*      */   }
/*      */   
/*      */   public Date getEstimatedEndTime(ParsedDateTime dtStart) throws ServiceException {
/*  169 */     if (dtStart == null)
/*  170 */       return null;
/*  171 */     return estimateEndTimeByUntilAndHardLimits(dtStart);
/*      */   }
/*      */   
/*      */   public static String listAsStr(List<? extends Object> l)
/*      */   {
/*  176 */     StringBuffer toRet = new StringBuffer();
/*  177 */     boolean first = true;
/*  178 */     for (Object obj : l) {
/*  179 */       if (!first) {
/*  180 */         toRet.append(',');
/*      */       } else
/*  182 */         first = false;
/*  183 */       toRet.append(obj.toString());
/*      */     }
/*      */     
/*  186 */     return toRet.toString();
/*      */   }
/*      */   
/*      */   public static void main(String[] args) {
/*  190 */     ICalTimeZone tzUTC = ICalTimeZone.getUTC();
/*  191 */     TimeZoneMap tzmap = new TimeZoneMap(tzUTC);
/*  192 */     ParsedDateTime dtStart = null;
/*      */     try {
/*  194 */       dtStart = ParsedDateTime.parse("20050101T123456", tzmap, tzUTC, tzUTC);
/*      */     } catch (ParseException e) {
/*  196 */       System.out.println("Caught ParseException at start: " + e);
/*      */     }
/*      */     
/*      */ 
/*      */ 
/*      */ 
/*  202 */     GregorianCalendar cal = new GregorianCalendar();
/*  203 */     cal.clear();
/*  204 */     cal.setTimeZone(tzUTC);
/*      */     
/*  206 */     cal.set(2005, 4, 15, 0, 0, 0);
/*  207 */     Date rangeStart = cal.getTime();
/*      */     
/*  209 */     cal.set(2006, 0, 1, 0, 0, 0);
/*  210 */     Date rangeEnd = cal.getTime();
/*      */     
/*      */     try
/*      */     {
/*  214 */       ZRecur test = new ZRecur("FREQ=DAILY;BYMONTH=5,6", tzmap);
/*  215 */       System.out.println("\n\n" + test.toString() + "\n-------------------------------------------------");
/*  216 */       List<Date> dateList = test.expandRecurrenceOverRange(dtStart, rangeStart.getTime(), rangeEnd.getTime());
/*  217 */       for (Date d : dateList) {
/*  218 */         cal.setTime(d);
/*  219 */         cal.setTimeZone(tzUTC);
/*  220 */         System.out.printf("%tc\n", new Object[] { cal });
/*      */       }
/*      */     } catch (ServiceException e) {
/*  223 */       System.out.println("Caught ServiceException" + e);
/*  224 */       e.printStackTrace();
/*      */     }
/*      */     try
/*      */     {
/*  228 */       ZRecur test = new ZRecur("FREQ=DAILY;BYMONTH=5,6;BYDAY=TH,-1MO", tzmap);
/*  229 */       System.out.println("\n\n" + test.toString() + "\n-------------------------------------------------");
/*  230 */       List<Date> dateList = test.expandRecurrenceOverRange(dtStart, rangeStart.getTime(), rangeEnd.getTime());
/*  231 */       for (Date d : dateList) {
/*  232 */         cal.setTime(d);
/*  233 */         cal.setTimeZone(tzUTC);
/*  234 */         System.out.printf("%tc\n", new Object[] { cal });
/*      */       }
/*      */     } catch (ServiceException e) {
/*  237 */       System.out.println("Caught ServiceException" + e);
/*  238 */       e.printStackTrace();
/*      */     }
/*      */     try
/*      */     {
/*  242 */       ZRecur test = new ZRecur("FREQ=DAILY;BYMONTH=5,6;BYMONTHDAY=1,3,5,7,9,31", tzmap);
/*  243 */       System.out.println("\n\n" + test.toString() + "\n-------------------------------------------------");
/*  244 */       List<Date> dateList = test.expandRecurrenceOverRange(dtStart, rangeStart.getTime(), rangeEnd.getTime());
/*  245 */       for (Date d : dateList) {
/*  246 */         cal.setTime(d);
/*  247 */         System.out.printf("%tc\n", new Object[] { cal });
/*      */       }
/*      */     } catch (ServiceException e) {
/*  250 */       System.out.println("Caught ServiceException" + e);
/*  251 */       e.printStackTrace();
/*      */     }
/*      */     try
/*      */     {
/*  255 */       ZRecur test = new ZRecur("FREQ=DAILY;BYMONTH=5,6;BYMONTHDAY=1,3,5,7,9,31;BYDAY=SU,SA", tzmap);
/*  256 */       System.out.println("\n\n" + test.toString() + "\n--------------------------------------------------------------");
/*  257 */       List<Date> dateList = test.expandRecurrenceOverRange(dtStart, rangeStart.getTime(), rangeEnd.getTime());
/*  258 */       for (Date d : dateList) {
/*  259 */         cal.setTime(d);
/*  260 */         System.out.printf("%tc\n", new Object[] { cal });
/*      */       }
/*      */     } catch (ServiceException e) {
/*  263 */       System.out.println("Caught ServiceException" + e);
/*  264 */       e.printStackTrace();
/*      */     }
/*      */     
/*      */     try
/*      */     {
/*  269 */       ZRecur test = new ZRecur("FREQ=DAILY;BYMONTH=5,6;BYMONTHDAY=1,3,5,7,9,31;BYDAY=SU,SA;BYHOUR=21,0", tzmap);
/*  270 */       System.out.println("\n\n" + test.toString() + "\n--------------------------------------------------------------");
/*  271 */       List<Date> dateList = test.expandRecurrenceOverRange(dtStart, rangeStart.getTime(), rangeEnd.getTime());
/*  272 */       for (Date d : dateList) {
/*  273 */         cal.setTime(d);
/*  274 */         System.out.printf("%tc\n", new Object[] { cal });
/*      */       }
/*      */     } catch (ServiceException e) {
/*  277 */       System.out.println("Caught ServiceException" + e);
/*  278 */       e.printStackTrace();
/*      */     }
/*      */     try
/*      */     {
/*  282 */       ZRecur test = new ZRecur("FREQ=DAILY;BYMONTH=5,6;BYMONTHDAY=1,3,5,7,9,31;BYDAY=SU;BYHOUR=21,0;BYMINUTE=23", tzmap);
/*  283 */       System.out.println("\n\n" + test.toString() + "\n--------------------------------------------------------------");
/*  284 */       List<Date> dateList = test.expandRecurrenceOverRange(dtStart, rangeStart.getTime(), rangeEnd.getTime());
/*  285 */       for (Date d : dateList) {
/*  286 */         cal.setTime(d);
/*  287 */         System.out.printf("%tc\n", new Object[] { cal });
/*      */       }
/*      */     } catch (ServiceException e) {
/*  290 */       System.out.println("Caught ServiceException" + e);
/*  291 */       e.printStackTrace();
/*      */     }
/*      */     try
/*      */     {
/*  295 */       ZRecur test = new ZRecur("FREQ=DAILY;BYMONTH=5,6;BYMONTHDAY=1,3,5,7,9,31;BYDAY=SU;BYHOUR=1,21,0;BYSECOND=0,59", tzmap);
/*  296 */       System.out.println("\n\n" + test.toString() + "\n--------------------------------------------------------------");
/*  297 */       List<Date> dateList = test.expandRecurrenceOverRange(dtStart, rangeStart.getTime(), rangeEnd.getTime());
/*  298 */       for (Date d : dateList) {
/*  299 */         cal.setTime(d);
/*  300 */         System.out.printf("%tc\n", new Object[] { cal });
/*      */       }
/*      */     } catch (ServiceException e) {
/*  303 */       System.out.println("Caught ServiceException" + e);
/*  304 */       e.printStackTrace();
/*      */     }
/*      */     
/*      */     try
/*      */     {
/*  309 */       ZRecur test = new ZRecur("FREQ=DAILY;BIYMONTH=5,6;BYMONTHDAY=1,3,5,7,9,31;BYDAY=SU;BYHOUR=1,21,0;BYSECOND=0,59;BYSETPOS=1,-1,3,1000,,-1000", tzmap);
/*  310 */       System.out.println("\n\n" + test.toString() + "\n--------------------------------------------------------------");
/*  311 */       List<Date> dateList = test.expandRecurrenceOverRange(dtStart, rangeStart.getTime(), rangeEnd.getTime());
/*  312 */       for (Date d : dateList) {
/*  313 */         cal.setTime(d);
/*  314 */         System.out.printf("%tc\n", new Object[] { cal });
/*      */       }
/*      */     } catch (ServiceException e) {
/*  317 */       System.out.println("Caught ServiceException" + e);
/*  318 */       e.printStackTrace();
/*      */     }
/*      */     try
/*      */     {
/*  322 */       ZRecur test = new ZRecur("FREQ=HOURLY;BIYMONTH=6;BYMONTHDAY=1,3;BYHOUR=2,14", tzmap);
/*  323 */       System.out.println("\n\n" + test.toString() + "\n--------------------------------------------------------------");
/*  324 */       List<Date> dateList = test.expandRecurrenceOverRange(dtStart, rangeStart.getTime(), rangeEnd.getTime());
/*  325 */       for (Date d : dateList) {
/*  326 */         cal.setTime(d);
/*  327 */         System.out.printf("%tc\n", new Object[] { cal });
/*      */       }
/*      */     } catch (ServiceException e) {
/*  330 */       System.out.println("Caught ServiceException" + e);
/*  331 */       e.printStackTrace();
/*      */     }
/*      */     try
/*      */     {
/*  335 */       ZRecur test = new ZRecur("FREQ=HOURLY;BIYMONTH=6;BYMONTHDAY=1;;BYMINUTE=10;BYSECOND=11,12", tzmap);
/*  336 */       System.out.println("\n\n" + test.toString() + "\n--------------------------------------------------------------");
/*  337 */       List<Date> dateList = test.expandRecurrenceOverRange(dtStart, rangeStart.getTime(), rangeEnd.getTime());
/*  338 */       for (Date d : dateList) {
/*  339 */         cal.setTime(d);
/*  340 */         System.out.printf("%tc\n", new Object[] { cal });
/*      */       }
/*      */     } catch (ServiceException e) {
/*  343 */       System.out.println("Caught ServiceException" + e);
/*  344 */       e.printStackTrace();
/*      */     }
/*      */     
/*      */ 
/*      */ 
/*  349 */     cal.set(2010, 0, 1, 0, 0, 0);
/*  350 */     rangeEnd = cal.getTime();
/*      */     try
/*      */     {
/*  353 */       ZRecur test = new ZRecur("FREQ=YEARLY", tzmap);
/*  354 */       System.out.println("\n\n" + test.toString() + "\n--------------------------------------------------------------");
/*  355 */       List<Date> dateList = test.expandRecurrenceOverRange(dtStart, rangeStart.getTime(), rangeEnd.getTime());
/*  356 */       for (Date d : dateList) {
/*  357 */         cal.setTime(d);
/*  358 */         System.out.printf("%tc\n", new Object[] { cal });
/*      */       }
/*      */     } catch (ServiceException e) {
/*  361 */       System.out.println("Caught ServiceException" + e);
/*  362 */       e.printStackTrace();
/*      */     }
/*      */     
/*      */     try
/*      */     {
/*  367 */       ZRecur test = new ZRecur("FREQ=YEARLY;BYYEARDAY=-1", tzmap);
/*  368 */       System.out.println("\n\n" + test.toString() + "\n--------------------------------------------------------------");
/*  369 */       List<Date> dateList = test.expandRecurrenceOverRange(dtStart, rangeStart.getTime(), rangeEnd.getTime());
/*  370 */       for (Date d : dateList) {
/*  371 */         cal.setTime(d);
/*  372 */         System.out.printf("%tc\n", new Object[] { cal });
/*      */       }
/*      */     } catch (ServiceException e) {
/*  375 */       System.out.println("Caught ServiceException" + e);
/*  376 */       e.printStackTrace();
/*      */     }
/*      */     try
/*      */     {
/*  380 */       ZRecur test = new ZRecur("FREQ=SECONDLY", tzmap);
/*  381 */       System.out.println("\n\n" + test.toString() + "\n--------------------------------------------------------------");
/*  382 */       List<Date> dateList = test.expandRecurrenceOverRange(dtStart, rangeStart.getTime(), rangeEnd.getTime());
/*  383 */       for (Date d : dateList) {
/*  384 */         cal.setTime(d);
/*  385 */         System.out.printf("%tc\n", new Object[] { cal });
/*      */       }
/*      */     } catch (ServiceException e) {
/*  388 */       System.out.println("Caught ServiceException" + e);
/*  389 */       e.printStackTrace();
/*      */     }
/*      */     try
/*      */     {
/*  393 */       ParsedDateTime myDtStart = ParsedDateTime.parse("16010101T020000", tzmap, tzUTC, tzUTC);
/*  394 */       ZRecur test = new ZRecur("FREQ=YEARLY;WKST=MO;INTERVAL=1;BYMONTH=12;BYDAY=-1SU", tzmap);
/*  395 */       System.out.println("\n\n" + test.toString() + "\n--------------------------------------------------------------");
/*  396 */       List<Date> dateList = test.expandRecurrenceOverRange(myDtStart, rangeStart.getTime(), rangeEnd.getTime());
/*  397 */       for (Date d : dateList) {
/*  398 */         cal.setTime(d);
/*  399 */         System.out.printf("%tc\n", new Object[] { cal });
/*      */       }
/*      */     } catch (ParseException e) {
/*  402 */       System.out.println("Caught ParseException" + e);
/*  403 */       e.printStackTrace();
/*      */     } catch (ServiceException e) {
/*  405 */       System.out.println("Caught ServiceException" + e);
/*  406 */       e.printStackTrace();
/*      */     }
/*      */     
/*  409 */     cal.set(2010, 0, 1, 0, 0, 0);
/*  410 */     rangeEnd = cal.getTime();
/*      */     try
/*      */     {
/*  413 */       ZRecur test = new ZRecur("FREQ=YEARLY;BYMONTH=12;BYDAY=1WE", tzmap);
/*  414 */       System.out.println("\n\n" + test.toString() + "\n--------------------------------------------------------------");
/*  415 */       List<Date> dateList = test.expandRecurrenceOverRange(dtStart, rangeStart.getTime(), rangeEnd.getTime());
/*  416 */       for (Date d : dateList) {
/*  417 */         cal.setTime(d);
/*  418 */         System.out.printf("%tc\n", new Object[] { cal });
/*      */       }
/*      */     } catch (ServiceException e) {
/*  421 */       System.out.println("Caught ServiceException" + e);
/*  422 */       e.printStackTrace();
/*      */     }
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*  428 */   private List<ZWeekDayNum> mByDayList = new ArrayList();
/*  429 */   private List<Integer> mByHourList = new ArrayList();
/*  430 */   private List<Integer> mByMinuteList = new ArrayList();
/*  431 */   private List<Integer> mByMonthDayList = new ArrayList();
/*  432 */   private List<Integer> mByMonthList = new ArrayList();
/*  433 */   private List<Integer> mBySecondList = new ArrayList();
/*      */   
/*  435 */   private List<Integer> mBySetPosList = new ArrayList();
/*  436 */   private List<Integer> mByWeekNoList = new ArrayList();
/*  437 */   private List<Integer> mByYearDayList = new ArrayList();
/*      */   
/*  439 */   private int mCount = 0;
/*  440 */   private Frequency mFreq = Frequency.WEEKLY;
/*  441 */   private int mInterval = 0;
/*  442 */   private ParsedDateTime mUntil = null;
/*  443 */   private ZWeekDay mWkSt = null;
/*      */   
/*      */   public ZRecur(String str, TimeZoneMap tzmap) throws ServiceException
/*      */   {
/*  447 */     parse(str, tzmap);
/*      */   }
/*      */   
/*      */   private ZRecur(ZRecur other) {
/*  451 */     this.mByDayList.addAll(other.mByDayList);
/*  452 */     this.mByHourList.addAll(other.mByHourList);
/*  453 */     this.mByMinuteList.addAll(other.mByMinuteList);
/*  454 */     this.mByMonthDayList.addAll(other.mByMonthDayList);
/*  455 */     this.mByMonthList.addAll(other.mByMonthList);
/*  456 */     this.mBySecondList.addAll(other.mBySecondList);
/*  457 */     this.mBySetPosList.addAll(other.mBySetPosList);
/*  458 */     this.mByWeekNoList.addAll(other.mByWeekNoList);
/*  459 */     this.mByYearDayList.addAll(other.mByYearDayList);
/*  460 */     this.mCount = other.mCount;
/*  461 */     this.mFreq = other.mFreq;
/*  462 */     this.mInterval = other.mInterval;
/*  463 */     this.mUntil = (other.mUntil == null ? null : (ParsedDateTime)other.mUntil.clone());
/*  464 */     this.mWkSt = other.mWkSt;
/*      */   }
/*      */   
/*      */   public Object clone()
/*      */   {
/*  469 */     return new ZRecur(this);
/*      */   }
/*      */   
/*      */   public List<Integer> getByHourList() {
/*  473 */     return this.mByHourList;
/*      */   }
/*      */   
/*      */   public void setByHourList(List<Integer> byHourList) {
/*  477 */     this.mByHourList = byHourList;
/*      */   }
/*      */   
/*      */   public List<Integer> getByMinuteList() {
/*  481 */     return this.mByMinuteList;
/*      */   }
/*      */   
/*      */   public void setByMinuteList(List<Integer> byMinuteList) {
/*  485 */     this.mByMinuteList = byMinuteList;
/*      */   }
/*      */   
/*      */   public List<Integer> getByMonthDayList() {
/*  489 */     return this.mByMonthDayList;
/*      */   }
/*      */   
/*      */   public void setByMonthDayList(List<Integer> byMonthDayList) {
/*  493 */     this.mByMonthDayList = byMonthDayList;
/*      */   }
/*      */   
/*      */   public List<Integer> getByMonthList() {
/*  497 */     return this.mByMonthList;
/*      */   }
/*      */   
/*      */   public void setByMonthList(List<Integer> byMonthList) {
/*  501 */     this.mByMonthList = byMonthList;
/*      */   }
/*      */   
/*      */   public List<Integer> getBySecondList() {
/*  505 */     return this.mBySecondList;
/*      */   }
/*      */   
/*      */   public void setBySecondList(List<Integer> bySecondList) {
/*  509 */     this.mBySecondList = bySecondList;
/*      */   }
/*      */   
/*      */   public List<Integer> getBySetPosList() {
/*  513 */     return this.mBySetPosList;
/*      */   }
/*      */   
/*      */   public void setBySetPosList(List<Integer> bySetPosList) {
/*  517 */     this.mBySetPosList = bySetPosList;
/*      */   }
/*      */   
/*      */   public List<Integer> getByWeekNoList() {
/*  521 */     return this.mByWeekNoList;
/*      */   }
/*      */   
/*      */   public void setByWeekNoList(List<Integer> byWeekNoList) {
/*  525 */     this.mByWeekNoList = byWeekNoList;
/*      */   }
/*      */   
/*      */   public List<Integer> getByYearDayList() {
/*  529 */     return this.mByYearDayList;
/*      */   }
/*      */   
/*      */   public void setByYearDayList(List<Integer> byYearDayList) {
/*  533 */     this.mByYearDayList = byYearDayList;
/*      */   }
/*      */   
/*      */   public int getCount() {
/*  537 */     return this.mCount;
/*      */   }
/*      */   
/*      */   public void setCount(int count) {
/*  541 */     this.mCount = count;
/*      */   }
/*      */   
/*      */   public Frequency getFrequency() {
/*  545 */     return this.mFreq;
/*      */   }
/*      */   
/*      */   public void setFrequency(Frequency freq) {
/*  549 */     this.mFreq = freq;
/*      */   }
/*      */   
/*      */   public int getInterval() {
/*  553 */     return this.mInterval;
/*      */   }
/*      */   
/*      */   public void setInterval(int interval) {
/*  557 */     this.mInterval = interval;
/*      */   }
/*      */   
/*      */   public ParsedDateTime getUntil() {
/*  561 */     return this.mUntil;
/*      */   }
/*      */   
/*      */   public void setUntil(ParsedDateTime until) {
/*  565 */     this.mUntil = until;
/*      */   }
/*      */   
/*      */   public ZWeekDay getWkSt() {
/*  569 */     return this.mWkSt;
/*      */   }
/*      */   
/*      */   public void setWkSt(ZWeekDay wkSt) {
/*  573 */     this.mWkSt = wkSt;
/*      */   }
/*      */   
/*      */   public void setByDayList(List<ZWeekDayNum> byDayList) {
/*  577 */     this.mByDayList = byDayList;
/*      */   }
/*      */   
/*      */   public List<ZWeekDayNum> getByDayList() {
/*  581 */     return this.mByDayList;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   public List<Date> expandRecurrenceOverRange(ParsedDateTime dtStart, long rangeStart, long rangeEnd)
/*      */     throws ServiceException
/*      */   {
/*  589 */     List<Date> toRet = new LinkedList();
/*      */     
/*  591 */     Date rangeStartDate = new Date(rangeStart);
/*      */     
/*      */ 
/*      */ 
/*  595 */     Date rangeEndDate = new Date(rangeEnd - 1000L);
/*  596 */     Date dtStartDate = new Date(dtStart.getUtcTime());
/*      */     Date earliestDate;
/*      */     Date earliestDate;
/*  599 */     if (dtStartDate.after(rangeStartDate)) {
/*  600 */       earliestDate = dtStartDate;
/*      */     } else {
/*  602 */       earliestDate = rangeStartDate;
/*      */     }
/*  604 */     if (this.mUntil != null) {
/*  605 */       Date until = this.mUntil.getDateForRecurUntil(dtStart.getTimeZone());
/*  606 */       if (until.before(rangeEndDate)) {
/*  607 */         rangeEndDate = until;
/*      */       }
/*      */     }
/*      */     
/*  611 */     int maxInstancesFromConfig = sExpansionLimits.maxInstances;
/*      */     int maxInstancesExpanded;
/*  613 */     int maxInstancesExpanded; if (maxInstancesFromConfig <= 0) {
/*  614 */       maxInstancesExpanded = this.mCount; } else { int maxInstancesExpanded;
/*  615 */       if (this.mCount <= 0) {
/*  616 */         maxInstancesExpanded = maxInstancesFromConfig;
/*      */       } else
/*  618 */         maxInstancesExpanded = Math.min(this.mCount, maxInstancesFromConfig); }
/*  619 */     int numInstancesExpanded = 1;
/*      */     
/*      */ 
/*  622 */     ParsedDateTime earliestDateTime = ParsedDateTime.fromUTCTime(earliestDate.getTime());
/*  623 */     Date hardEndDate = getEstimatedEndTime(earliestDateTime);
/*  624 */     if (hardEndDate.before(rangeEndDate)) {
/*  625 */       rangeEndDate = hardEndDate;
/*      */     }
/*  627 */     if (rangeEndDate.before(earliestDate)) {
/*  628 */       ZimbraLog.calendar.debug("Expanding recurrence over range where range end %s is before earliest date %s", new Object[] { DateUtil.formatDate(rangeEndDate), DateUtil.formatDate(earliestDate) });
/*      */       
/*  630 */       return toRet;
/*      */     }
/*      */     
/*  633 */     GregorianCalendar cur = dtStart.getCalendarCopy();
/*  634 */     int baseMonthDay = cur.get(5);
/*  635 */     boolean baseIsLeapDay = (baseMonthDay == 29) && (cur.get(2) == 1);
/*      */     
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*  649 */     int interval = this.mInterval;
/*  650 */     if (interval <= 0) {
/*  651 */       interval = 1;
/*      */     }
/*      */     
/*      */ 
/*  655 */     if ((!dtStartDate.before(earliestDate)) && (!dtStartDate.after(rangeEndDate))) {
/*  656 */       toRet.add(dtStartDate);
/*      */     }
/*  658 */     int numConsecutiveIterationsWithoutMatchingInstance = 0;
/*  659 */     boolean pastHardEndTime = false;
/*  660 */     long numIterations = 0L;
/*  661 */     while ((!pastHardEndTime) && ((maxInstancesExpanded <= 0) || (numInstancesExpanded < maxInstancesExpanded))) {
/*  662 */       numIterations += 1L;
/*  663 */       boolean curIsAtOrAfterEarliestDate = !cur.getTime().before(earliestDate);
/*  664 */       boolean curIsAfterEndDate = cur.getTime().after(rangeEndDate);
/*  665 */       List<Calendar> addList = new LinkedList();
/*      */       
/*  667 */       switch (this.mFreq)
/*      */       {
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */       case HOURLY: 
/*  678 */         if ((checkMonthList(cur)) && 
/*      */         
/*      */ 
/*  681 */           (checkYearDayList(cur)) && 
/*      */           
/*      */ 
/*  684 */           (checkMonthDayList(cur)) && 
/*      */           
/*      */ 
/*  687 */           (checkDayList(cur)) && 
/*      */           
/*      */ 
/*  690 */           (checkHourList(cur)))
/*      */         {
/*      */ 
/*  693 */           addList.add((Calendar)cur.clone());
/*      */           
/*  695 */           cur.add(11, interval);
/*      */           
/*  697 */           addList = expandHourList(addList);
/*  698 */           addList = expandMinuteList(addList);
/*  699 */           addList = expandSecondList(addList);
/*      */         }
/*  701 */         break;
/*      */       
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */       case DAILY: 
/*  738 */         if ((checkMonthList(cur)) && 
/*      */         
/*      */ 
/*  741 */           (checkYearDayList(cur)) && 
/*      */           
/*      */ 
/*  744 */           (checkMonthDayList(cur)) && 
/*      */           
/*      */ 
/*  747 */           (checkDayList(cur)))
/*      */         {
/*      */ 
/*  750 */           addList.add((Calendar)cur.clone());
/*      */           
/*  752 */           cur.add(6, interval);
/*      */           
/*  754 */           addList = expandHourList(addList);
/*  755 */           addList = expandMinuteList(addList);
/*  756 */           addList = expandSecondList(addList); }
/*  757 */         break;
/*      */       
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */       case WEEKLY: 
/*  790 */         if ((checkMonthList(cur)) && 
/*      */         
/*      */ 
/*  793 */           (checkYearDayList(cur)) && 
/*      */           
/*      */ 
/*  796 */           (checkMonthDayList(cur)))
/*      */         {
/*      */ 
/*  799 */           addList.add((Calendar)cur.clone());
/*      */           
/*  801 */           cur.add(3, interval);
/*      */           
/*  803 */           addList = expandDayListForWeekly(addList);
/*  804 */           addList = expandHourList(addList);
/*  805 */           addList = expandMinuteList(addList);
/*  806 */           addList = expandSecondList(addList); }
/*  807 */         break;
/*      */       case MONTHLY: 
/*  809 */         if ((checkMonthList(cur)) && 
/*      */         
/*      */ 
/*  812 */           (checkYearDayList(cur)))
/*      */         {
/*      */ 
/*  815 */           addList.add((Calendar)cur.clone());
/*      */           
/*  817 */           cur.set(5, 1);
/*  818 */           cur.add(2, interval);
/*  819 */           int daysInMonth = cur.getActualMaximum(5);
/*  820 */           cur.set(5, Math.min(baseMonthDay, daysInMonth));
/*      */           
/*  822 */           addList = expandMonthDayList(addList);
/*  823 */           addList = expandDayListForMonthlyYearly(addList);
/*  824 */           addList = expandHourList(addList);
/*  825 */           addList = expandMinuteList(addList);
/*  826 */           addList = expandSecondList(addList);
/*      */         }
/*  828 */         break;
/*      */       
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */       case YEARLY: 
/*  840 */         if (baseIsLeapDay)
/*      */         {
/*      */ 
/*      */ 
/*  844 */           cur.set(5, cur.getActualMaximum(5));
/*      */         }
/*  846 */         if (ignoreYearForRecurrenceExpansion(cur, baseIsLeapDay)) {
/*  847 */           cur.add(1, interval);
/*      */         }
/*      */         else {
/*  850 */           addList.add((Calendar)cur.clone());
/*      */           
/*  852 */           cur.add(1, interval);
/*      */           
/*  854 */           addList = expandMonthList(addList);
/*  855 */           addList = expandYearDayList(addList);
/*      */           
/*  857 */           addList = expandMonthDayList(addList);
/*  858 */           addList = expandDayListForMonthlyYearly(addList);
/*  859 */           addList = expandHourList(addList);
/*  860 */           addList = expandMinuteList(addList);
/*  861 */           addList = expandSecondList(addList);
/*      */         }
/*  863 */         break;
/*      */       
/*      */       default: 
/*  866 */         return toRet;
/*      */         
/*      */ 
/*  869 */         addList = handleSetPos(addList);
/*      */         
/*  871 */         boolean noInstanceFound = true;
/*  872 */         boolean foundInstancePastEndDate = false;
/*      */         
/*  874 */         for (Calendar addCal : addList) {
/*  875 */           Date toAdd = addCal.getTime();
/*      */           
/*      */ 
/*      */ 
/*  879 */           if (toAdd.compareTo(dtStartDate) == 0) {
/*  880 */             noInstanceFound = false;
/*      */ 
/*      */           }
/*      */           else
/*      */           {
/*      */ 
/*  886 */             if (toAdd.after(dtStartDate)) {
/*  887 */               numInstancesExpanded++;
/*      */             }
/*  889 */             if (!toAdd.after(rangeEndDate)) {
/*  890 */               if (!toAdd.before(earliestDate)) {
/*  891 */                 toRet.add(toAdd);
/*  892 */                 noInstanceFound = false;
/*      */               }
/*      */             } else {
/*  895 */               foundInstancePastEndDate = true;
/*  896 */               break;
/*      */             }
/*      */             
/*  899 */             if ((maxInstancesExpanded > 0) && (numInstancesExpanded >= maxInstancesExpanded)) {
/*      */               break;
/*      */             }
/*      */           }
/*      */         }
/*      */         
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*  912 */         if (curIsAtOrAfterEarliestDate) {
/*  913 */           if (noInstanceFound) {
/*  914 */             numConsecutiveIterationsWithoutMatchingInstance++;
/*      */           } else
/*  916 */             numConsecutiveIterationsWithoutMatchingInstance = 0;
/*  917 */           if (numConsecutiveIterationsWithoutMatchingInstance >= 4) {
/*  918 */             ZimbraLog.calendar.warn("Invalid recurrence rule: " + toString());
/*  919 */             return toRet;
/*      */           }
/*      */         }
/*      */         
/*  923 */         pastHardEndTime = (foundInstancePastEndDate) || ((noInstanceFound) && (curIsAfterEndDate)); }
/*      */       
/*      */     }
/*  926 */     return toRet;
/*      */   }
/*      */   
/*      */   public String toString()
/*      */   {
/*  931 */     StringBuffer toRet = new StringBuffer("FREQ=").append(this.mFreq);
/*      */     
/*  933 */     if (this.mUntil != null) {
/*  934 */       toRet.append(';').append("UNTIL=");
/*  935 */       toRet.append(this.mUntil.getDateTimePartString(false));
/*      */     }
/*  937 */     if (this.mCount > 0)
/*  938 */       toRet.append(';').append("COUNT=").append(this.mCount);
/*  939 */     if (this.mInterval > 0)
/*  940 */       toRet.append(';').append("INTERVAL=").append(this.mInterval);
/*  941 */     if (this.mBySecondList.size() > 0)
/*  942 */       toRet.append(';').append("BYSECOND=").append(listAsStr(this.mBySecondList));
/*  943 */     if (this.mByMinuteList.size() > 0)
/*  944 */       toRet.append(';').append("BYMINUTE=").append(listAsStr(this.mByMinuteList));
/*  945 */     if (this.mByHourList.size() > 0)
/*  946 */       toRet.append(';').append("BYHOUR=").append(listAsStr(this.mByHourList));
/*  947 */     if (this.mByDayList.size() > 0)
/*  948 */       toRet.append(';').append("BYDAY=").append(listAsStr(this.mByDayList));
/*  949 */     if (this.mByMonthDayList.size() > 0)
/*  950 */       toRet.append(';').append("BYMONTHDAY=").append(listAsStr(this.mByMonthDayList));
/*  951 */     if (this.mByYearDayList.size() > 0)
/*  952 */       toRet.append(';').append("BYYEARDAY=").append(listAsStr(this.mByYearDayList));
/*  953 */     if (this.mByWeekNoList.size() > 0)
/*  954 */       toRet.append(';').append("BYWEEKNO=").append(listAsStr(this.mByWeekNoList));
/*  955 */     if (this.mByMonthList.size() > 0)
/*  956 */       toRet.append(';').append("BYMONTH=").append(listAsStr(this.mByMonthList));
/*  957 */     if (this.mBySetPosList.size() > 0) {
/*  958 */       toRet.append(';').append("BYSETPOS=").append(listAsStr(this.mBySetPosList));
/*      */     }
/*  960 */     return toRet.toString();
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   private boolean checkDayList(GregorianCalendar cal)
/*      */   {
/*  971 */     assert ((this.mFreq != Frequency.MONTHLY) && (this.mFreq != Frequency.YEARLY) && (this.mFreq != Frequency.WEEKLY));
/*      */     
/*  973 */     if (this.mByDayList.size() > 0) {
/*  974 */       for (ZWeekDayNum listCur : this.mByDayList) {
/*  975 */         int curDayOfWeek = cal.get(7);
/*  976 */         if (listCur.mDay.getCalendarDay() == curDayOfWeek) {
/*  977 */           return true;
/*      */         }
/*      */         
/*      */ 
/*      */ 
/*  982 */         if (listCur.mDay.getCalendarDay() > curDayOfWeek) {
/*  983 */           cal.set(7, listCur.mDay.getCalendarDay());
/*  984 */           return false;
/*      */         }
/*      */       }
/*      */       
/*      */ 
/*      */ 
/*  990 */       cal.set(7, ((ZWeekDayNum)this.mByDayList.get(0)).mDay.getCalendarDay());
/*  991 */       cal.add(3, 1);
/*  992 */       return false;
/*      */     }
/*  994 */     return true;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   private boolean checkHourList(GregorianCalendar cal)
/*      */   {
/* 1003 */     if (this.mByHourList.size() > 0) {
/* 1004 */       for (Integer cur : this.mByHourList) {
/* 1005 */         int curHour = cal.get(11);
/* 1006 */         if (curHour == cur.intValue()) {
/* 1007 */           return true;
/*      */         }
/*      */         
/*      */ 
/*      */ 
/* 1012 */         if (cur.intValue() > curHour) {
/* 1013 */           cal.set(11, cur.intValue());
/* 1014 */           return false;
/*      */         }
/*      */       }
/*      */       
/*      */ 
/*      */ 
/* 1020 */       cal.set(10, ((Integer)this.mByHourList.get(0)).intValue());
/* 1021 */       cal.add(6, 1);
/* 1022 */       return false;
/*      */     }
/* 1024 */     return true;
/*      */   }
/*      */   
/*      */   private boolean checkMonthDayList(GregorianCalendar cal) {
/* 1028 */     if (this.mByMonthDayList.size() > 0) {
/* 1029 */       for (Integer cur : this.mByMonthDayList) {
/* 1030 */         int curMonthDay = cal.get(5);
/* 1031 */         if (cur.intValue() == curMonthDay) {
/* 1032 */           return true;
/*      */         }
/*      */         
/*      */ 
/*      */ 
/* 1037 */         if (cur.intValue() > curMonthDay) {
/* 1038 */           cal.set(5, cur.intValue());
/* 1039 */           return false;
/*      */         }
/*      */       }
/*      */       
/*      */ 
/*      */ 
/* 1045 */       cal.set(5, ((Integer)this.mByMonthDayList.get(0)).intValue());
/* 1046 */       cal.add(2, 1);
/* 1047 */       return false;
/*      */     }
/* 1049 */     return true;
/*      */   }
/*      */   
/*      */   private boolean checkMonthList(GregorianCalendar cal) {
/* 1053 */     if (this.mByMonthList.size() > 0) {
/* 1054 */       for (Integer cur : this.mByMonthList) {
/* 1055 */         int curMonth = cal.get(2) + 1;
/* 1056 */         if (cur.intValue() == curMonth) {
/* 1057 */           return true;
/*      */         }
/*      */         
/*      */ 
/*      */ 
/* 1062 */         if (cur.intValue() > curMonth) {
/* 1063 */           cal.set(2, cur.intValue() - 1);
/* 1064 */           return false;
/*      */         }
/*      */       }
/*      */       
/*      */ 
/*      */ 
/* 1070 */       cal.set(2, ((Integer)this.mByMonthList.get(0)).intValue() - 1);
/* 1071 */       cal.add(1, 1);
/* 1072 */       return false;
/*      */     }
/* 1074 */     return true;
/*      */   }
/*      */   
/*      */   private boolean checkYearDayList(GregorianCalendar cal) {
/* 1078 */     if (this.mByYearDayList.size() > 0) {
/* 1079 */       for (Integer cur : this.mByYearDayList) {
/* 1080 */         int curYearDay = cal.get(6);
/* 1081 */         if (cur.intValue() == curYearDay) {
/* 1082 */           return true;
/*      */         }
/*      */         
/*      */ 
/*      */ 
/* 1087 */         if (cur.intValue() > curYearDay) {
/* 1088 */           cal.set(6, cur.intValue());
/* 1089 */           return false;
/*      */         }
/*      */       }
/*      */       
/*      */ 
/*      */ 
/* 1095 */       cal.set(6, ((Integer)this.mByYearDayList.get(0)).intValue());
/* 1096 */       cal.add(1, 1);
/* 1097 */       return false;
/*      */     }
/* 1099 */     return true;
/*      */   }
/*      */   
/*      */   private List<Calendar> expandDayListForMonthlyYearly(List<Calendar> list)
/*      */   {
/* 1104 */     assert ((this.mFreq == Frequency.MONTHLY) || (this.mFreq == Frequency.YEARLY));
/*      */     
/* 1106 */     if (this.mByDayList.size() <= 0) {
/* 1107 */       return list;
/*      */     }
/* 1109 */     List<Calendar> toRet = new ArrayList();
/* 1110 */     Set<Integer> months = new HashSet();
/*      */     
/*      */ 
/* 1113 */     for (Iterator i$ = list.iterator(); i$.hasNext();) { cur = (Calendar)i$.next();
/* 1114 */       curYear = cur.get(1);
/* 1115 */       curMonth = cur.get(2);
/* 1116 */       if (!months.contains(Integer.valueOf(curMonth))) {
/* 1117 */         months.add(Integer.valueOf(curMonth));
/*      */         
/* 1119 */         for (ZWeekDayNum day : this.mByDayList)
/*      */         {
/*      */ 
/* 1122 */           ArrayList<Integer> matching = new ArrayList();
/*      */           
/* 1124 */           cur.set(5, 1);
/*      */           do {
/* 1126 */             if (cur.get(7) == day.mDay.getCalendarDay())
/* 1127 */               matching.add(Integer.valueOf(cur.get(5)));
/* 1128 */             cur.add(5, 1);
/* 1129 */           } while (cur.get(2) == curMonth);
/*      */           
/* 1131 */           cur.set(2, curMonth);
/* 1132 */           cur.set(1, curYear);
/*      */           
/* 1134 */           if (day.mOrdinal == 0) {
/* 1135 */             for (Integer matchDay : matching) {
/* 1136 */               cur.set(5, matchDay.intValue());
/* 1137 */               toRet.add((Calendar)cur.clone());
/*      */             }
/*      */           }
/* 1140 */           else if (day.mOrdinal > 0) {
/* 1141 */             if (day.mOrdinal <= matching.size()) {
/* 1142 */               cur.set(5, ((Integer)matching.get(day.mOrdinal - 1)).intValue());
/* 1143 */               toRet.add((Calendar)cur.clone());
/*      */             }
/*      */           }
/* 1146 */           else if (-1 * day.mOrdinal <= matching.size()) {
/* 1147 */             cur.set(5, ((Integer)matching.get(matching.size() + day.mOrdinal)).intValue());
/* 1148 */             toRet.add((Calendar)cur.clone());
/*      */           }
/*      */         }
/*      */       }
/*      */     }
/*      */     
/*      */     Calendar cur;
/*      */     
/*      */     int curYear;
/*      */     int curMonth;
/* 1158 */     assert ((toRet instanceof ArrayList));
/* 1159 */     Collections.sort(toRet);
/*      */     
/* 1161 */     return toRet;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   private boolean ignoreYearForRecurrenceExpansion(Calendar cur, boolean baseIsLeapDay)
/*      */   {
/* 1180 */     boolean ignoreThisYear = false;
/* 1181 */     if ((baseIsLeapDay) && (cur.get(5) != 29)) {
/* 1182 */       ignoreThisYear = isSimpleRecurrence();
/* 1183 */       if ((!ignoreThisYear) && 
/* 1184 */         (this.mByMonthDayList.size() == 1) && (((Integer)this.mByMonthDayList.get(0)).intValue() == 29)) {
/* 1185 */         ignoreThisYear = (this.mByMonthList.isEmpty()) || ((this.mByMonthList.size() == 1) && (((Integer)this.mByMonthList.get(0)).intValue() == 2));
/*      */       }
/*      */     }
/*      */     
/*      */ 
/* 1190 */     return ignoreThisYear;
/*      */   }
/*      */   
/*      */   private boolean isSimpleRecurrence() {
/* 1194 */     if (!this.mByDayList.isEmpty()) return false;
/* 1195 */     if (!this.mByHourList.isEmpty()) return false;
/* 1196 */     if (!this.mByMinuteList.isEmpty()) return false;
/* 1197 */     if (!this.mByMonthDayList.isEmpty()) return false;
/* 1198 */     if (!this.mByMonthList.isEmpty()) return false;
/* 1199 */     if (!this.mBySecondList.isEmpty()) return false;
/* 1200 */     if (!this.mBySetPosList.isEmpty()) return false;
/* 1201 */     if (!this.mByWeekNoList.isEmpty()) return false;
/* 1202 */     if (!this.mByYearDayList.isEmpty()) return false;
/* 1203 */     return true;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */   private List<Calendar> expandDayListForWeekly(List<Calendar> list)
/*      */   {
/* 1215 */     assert (this.mFreq == Frequency.WEEKLY);
/*      */     
/* 1217 */     if (this.mByDayList.size() <= 0) {
/* 1218 */       return list;
/*      */     }
/* 1220 */     List<Calendar> toRet = new LinkedList();
/*      */     
/* 1222 */     for (Iterator i$ = list.iterator(); i$.hasNext();) { cur = (Calendar)i$.next();
/* 1223 */       for (ZWeekDayNum day : this.mByDayList) {
/* 1224 */         cur.set(7, day.mDay.getCalendarDay());
/* 1225 */         toRet.add((Calendar)cur.clone());
/*      */       }
/*      */     }
/*      */     Calendar cur;
/* 1229 */     return toRet;
/*      */   }
/*      */   
/*      */   private List<Calendar> expandHourList(List<Calendar> list)
/*      */   {
/* 1234 */     assert ((this.mFreq == Frequency.DAILY) || (this.mFreq == Frequency.WEEKLY) || (this.mFreq == Frequency.MONTHLY) || (this.mFreq == Frequency.YEARLY));
/*      */     
/* 1236 */     if (this.mByHourList.size() <= 0) {
/* 1237 */       return list;
/*      */     }
/* 1239 */     List<Calendar> toRet = new LinkedList();
/*      */     
/* 1241 */     for (Iterator i$ = list.iterator(); i$.hasNext();) { cur = (Calendar)i$.next();
/* 1242 */       for (Integer hour : this.mByHourList) {
/* 1243 */         cur.set(11, hour.intValue());
/* 1244 */         toRet.add((Calendar)cur.clone());
/*      */       }
/*      */     }
/*      */     Calendar cur;
/* 1248 */     return toRet;
/*      */   }
/*      */   
/*      */   private List<Calendar> expandMinuteList(List<Calendar> list)
/*      */   {
/* 1253 */     assert ((this.mFreq != Frequency.MINUTELY) && (this.mFreq != Frequency.SECONDLY));
/*      */     
/* 1255 */     if (this.mByMinuteList.size() <= 0) {
/* 1256 */       return list;
/*      */     }
/* 1258 */     List<Calendar> toRet = new LinkedList();
/*      */     
/* 1260 */     for (Iterator i$ = list.iterator(); i$.hasNext();) { cur = (Calendar)i$.next();
/* 1261 */       for (Integer minute : this.mByMinuteList) {
/* 1262 */         cur.set(12, minute.intValue());
/* 1263 */         toRet.add((Calendar)cur.clone());
/*      */       }
/*      */     }
/*      */     Calendar cur;
/* 1267 */     return toRet;
/*      */   }
/*      */   
/*      */   private List<Calendar> expandMonthDayList(List<Calendar> list)
/*      */   {
/* 1272 */     assert ((this.mFreq == Frequency.MONTHLY) || (this.mFreq == Frequency.YEARLY));
/*      */     
/* 1274 */     if (this.mByMonthDayList.size() <= 0) {
/* 1275 */       return list;
/*      */     }
/* 1277 */     List<Calendar> toRet = new LinkedList();
/*      */     
/* 1279 */     for (Iterator i$ = list.iterator(); i$.hasNext();) { cur = (Calendar)i$.next();
/* 1280 */       curMonth = cur.get(2);
/* 1281 */       lastMonthDay = cur.getActualMaximum(5);
/* 1282 */       seenLastMonthDay = false;
/* 1283 */       for (Integer moday : this.mByMonthDayList)
/* 1284 */         if (moday.intValue() != 0) {
/* 1285 */           if (moday.intValue() > 0) {
/* 1286 */             if (moday.intValue() >= lastMonthDay) {
/* 1287 */               if (seenLastMonthDay)
/*      */                 continue;
/* 1289 */               seenLastMonthDay = true;
/* 1290 */               moday = Integer.valueOf(lastMonthDay);
/*      */             }
/* 1292 */             cur.set(5, moday.intValue());
/*      */           } else {
/* 1294 */             if (moday.intValue() == -1) {
/* 1295 */               if (seenLastMonthDay)
/*      */                 continue;
/* 1297 */               seenLastMonthDay = true;
/*      */             }
/* 1299 */             cur.set(5, 1);
/* 1300 */             cur.roll(5, moday.intValue());
/*      */           }
/* 1302 */           assert (cur.get(2) == curMonth);
/* 1303 */           toRet.add((Calendar)cur.clone()); } }
/*      */     Calendar cur;
/*      */     int curMonth;
/*      */     int lastMonthDay;
/*      */     boolean seenLastMonthDay;
/* 1308 */     return toRet;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   private List<Calendar> expandMonthList(List<Calendar> list)
/*      */   {
/* 1315 */     assert (this.mFreq == Frequency.YEARLY);
/*      */     
/* 1317 */     if (this.mByMonthList.size() <= 0) {
/* 1318 */       return list;
/*      */     }
/* 1320 */     List<Calendar> toRet = new LinkedList();
/*      */     
/* 1322 */     for (Iterator i$ = list.iterator(); i$.hasNext();) { cur = (Calendar)i$.next();
/* 1323 */       for (Integer month : this.mByMonthList) {
/* 1324 */         cur.set(2, month.intValue() - 1);
/*      */         
/* 1326 */         toRet.add((Calendar)cur.clone());
/*      */       }
/*      */     }
/*      */     Calendar cur;
/* 1330 */     return toRet;
/*      */   }
/*      */   
/*      */ 
/*      */ 
/*      */   private List<Calendar> expandSecondList(List<Calendar> list)
/*      */   {
/* 1337 */     assert (this.mFreq != Frequency.SECONDLY);
/*      */     
/* 1339 */     if (this.mBySecondList.size() <= 0) {
/* 1340 */       return list;
/*      */     }
/* 1342 */     List<Calendar> toRet = new LinkedList();
/*      */     
/* 1344 */     for (Iterator i$ = list.iterator(); i$.hasNext();) { cur = (Calendar)i$.next();
/* 1345 */       for (Integer second : this.mBySecondList) {
/* 1346 */         cur.set(13, second.intValue());
/* 1347 */         toRet.add((Calendar)cur.clone());
/*      */       }
/*      */     }
/*      */     Calendar cur;
/* 1351 */     return toRet;
/*      */   }
/*      */   
/*      */ 
/*      */   private List<Calendar> expandYearDayList(List<Calendar> list)
/*      */   {
/* 1357 */     assert (this.mFreq == Frequency.YEARLY);
/*      */     
/* 1359 */     if (this.mByYearDayList.size() <= 0) {
/* 1360 */       return list;
/*      */     }
/* 1362 */     List<Calendar> toRet = new LinkedList();
/* 1363 */     Set<Integer> years = new HashSet();
/*      */     
/*      */ 
/* 1366 */     for (Iterator i$ = list.iterator(); i$.hasNext();) { cur = (Calendar)i$.next();
/* 1367 */       int curYear = cur.get(1);
/* 1368 */       if (!years.contains(Integer.valueOf(curYear))) {
/* 1369 */         years.add(Integer.valueOf(curYear));
/*      */         
/* 1371 */         for (Integer yearDay : this.mByYearDayList)
/*      */         {
/* 1373 */           if (yearDay.intValue() > 0) {
/* 1374 */             cur.set(6, yearDay.intValue());
/*      */           } else {
/* 1376 */             cur.set(6, 1);
/* 1377 */             cur.roll(6, yearDay.intValue());
/*      */           }
/*      */           
/* 1380 */           toRet.add((Calendar)cur.clone());
/*      */         }
/*      */       }
/*      */     }
/*      */     Calendar cur;
/* 1385 */     return toRet;
/*      */   }
/*      */   
/*      */   private List<Calendar> handleSetPos(List<Calendar> list)
/*      */   {
/* 1390 */     if (this.mBySetPosList.size() <= 0) {
/* 1391 */       return list;
/*      */     }
/*      */     
/* 1394 */     Calendar[] array = new Calendar[list.size()];
/* 1395 */     array = (Calendar[])list.toArray(array);
/*      */     
/* 1397 */     LinkedList<Calendar> toRet = new LinkedList();
/*      */     
/* 1399 */     ArrayList<Integer> idxsToInclude = new ArrayList();
/*      */     
/* 1401 */     for (Integer cur : this.mBySetPosList) {
/* 1402 */       int idx = cur.intValue();
/* 1403 */       if ((idx >= 65170) && (idx <= 366) && (idx != 0)) {
/* 1404 */         if (idx > 0) {
/* 1405 */           idx--;
/*      */         } else {
/* 1407 */           idx = array.length + idx;
/*      */         }
/* 1409 */         if ((idx >= 0) && (idx < array.length) && 
/* 1410 */           (!idxsToInclude.contains(Integer.valueOf(idx)))) {
/* 1411 */           idxsToInclude.add(Integer.valueOf(idx));
/*      */         }
/*      */       }
/*      */     }
/* 1415 */     Collections.sort(idxsToInclude);
/*      */     
/* 1417 */     for (Integer idx : idxsToInclude) {
/* 1418 */       toRet.add(array[idx.intValue()]);
/*      */     }
/*      */     
/* 1421 */     return toRet;
/*      */   }
/*      */   
/*      */   private void parse(String str, TimeZoneMap tzmap) throws ServiceException {
/*      */     try {
/* 1426 */       int numByParts = 0;
/* 1427 */       for (String tok : str.split("\\s*;\\s*")) {
/* 1428 */         String[] s = tok.split("\\s*=\\s*");
/* 1429 */         if (s.length != 2) {
/* 1430 */           if (ZimbraLog.calendar.isDebugEnabled()) {
/* 1431 */             ZimbraLog.calendar.debug(new Formatter().format("Parse error for recur: \"%s\" at token \"%s\"", new Object[] { str, tok }));
/*      */           }
/*      */         }
/*      */         else {
/* 1435 */           String rhs = s[1];
/*      */           
/* 1437 */           rhs = rhs.replaceAll("\\s+", "");
/*      */           try
/*      */           {
/* 1440 */             switch (Tokens.valueOf(s[0])) {
/*      */             case FREQ: 
/* 1442 */               this.mFreq = Frequency.valueOf(rhs);
/* 1443 */               break;
/*      */             case UNTIL: 
/* 1445 */               ParsedDateTime until = ParsedDateTime.parse(rhs, tzmap);
/* 1446 */               if (until != null)
/*      */               {
/*      */ 
/*      */ 
/* 1450 */                 if (until.hasTime())
/* 1451 */                   until.toUTC();
/* 1452 */                 this.mUntil = until;
/*      */               }
/*      */               break;
/*      */             case COUNT: 
/* 1456 */               this.mCount = Integer.parseInt(rhs);
/* 1457 */               break;
/*      */             case INTERVAL: 
/* 1459 */               this.mInterval = Integer.parseInt(rhs);
/* 1460 */               break;
/*      */             case BYSECOND: 
/* 1462 */               numByParts++;
/* 1463 */               parseIntList(rhs, this.mBySecondList, 0, 59, false);
/* 1464 */               break;
/*      */             case BYMINUTE: 
/* 1466 */               numByParts++;
/* 1467 */               parseIntList(rhs, this.mByMinuteList, 0, 59, false);
/* 1468 */               break;
/*      */             case BYHOUR: 
/* 1470 */               numByParts++;
/* 1471 */               parseIntList(rhs, this.mByHourList, 0, 23, false);
/* 1472 */               break;
/*      */             case BYDAY: 
/* 1474 */               numByParts++;
/* 1475 */               parseByDayList(rhs, this.mByDayList);
/* 1476 */               break;
/*      */             case BYMONTHDAY: 
/* 1478 */               numByParts++;
/* 1479 */               parseIntList(rhs, this.mByMonthDayList, -31, 31, true);
/* 1480 */               break;
/*      */             case BYYEARDAY: 
/* 1482 */               numByParts++;
/* 1483 */               parseIntList(rhs, this.mByYearDayList, 65170, 366, true);
/* 1484 */               break;
/*      */             case BYWEEKNO: 
/* 1486 */               numByParts++;
/* 1487 */               parseIntList(rhs, this.mByWeekNoList, -53, 53, true);
/* 1488 */               break;
/*      */             case BYMONTH: 
/* 1490 */               numByParts++;
/* 1491 */               parseIntList(rhs, this.mByMonthList, 1, 12, false);
/* 1492 */               break;
/*      */             case BYSETPOS: 
/* 1494 */               numByParts++;
/* 1495 */               parseIntList(rhs, this.mBySetPosList, Integer.MIN_VALUE, Integer.MAX_VALUE, true);
/* 1496 */               break;
/*      */             case WKST: 
/* 1498 */               this.mWkSt = ZWeekDay.valueOf(rhs);
/*      */             }
/*      */           }
/*      */           catch (IllegalArgumentException e) {
/* 1502 */             ZimbraLog.calendar.warn("Skipping RECUR token: \"%s\" in Recur \"%s\" due to parse error", s[0], str, e);
/*      */           }
/*      */         }
/*      */       }
/*      */       
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/*      */ 
/* 1513 */       if ((numByParts == 2) && (Frequency.MONTHLY.equals(this.mFreq)) && (this.mByDayList.size() == 1) && (((ZWeekDayNum)this.mByDayList.get(0)).mOrdinal == 0) && (this.mBySetPosList.size() == 1))
/*      */       {
/* 1515 */         ((ZWeekDayNum)this.mByDayList.get(0)).mOrdinal = ((Integer)this.mBySetPosList.get(0)).intValue();
/* 1516 */         this.mBySetPosList.clear();
/*      */       }
/*      */     } catch (ParseException e) {
/* 1519 */       throw ServiceException.FAILURE("Parse error for recur \"" + str + "\"", e);
/*      */     }
/*      */   }
/*      */   
/*      */   private static int parseSignedInt(String str) {
/* 1524 */     if (str == null)
/* 1525 */       throw new NumberFormatException("null is not a number");
/* 1526 */     int len = str.length();
/* 1527 */     if (len == 0)
/* 1528 */       throw new NumberFormatException("empty string is not a number");
/* 1529 */     int num = 0;
/* 1530 */     if (str.charAt(0) == '+') {
/* 1531 */       if (len == 1)
/* 1532 */         throw new NumberFormatException("+ is not a number");
/* 1533 */       num = Integer.parseInt(str.substring(1));
/*      */     } else {
/* 1535 */       num = Integer.parseInt(str);
/*      */     }
/* 1537 */     return num;
/*      */   }
/*      */   
/*      */   private static int parseUnsignedInt(String str) {
/* 1541 */     if (str == null)
/* 1542 */       throw new NumberFormatException("null is not a number");
/* 1543 */     int len = str.length();
/* 1544 */     if (len == 0)
/* 1545 */       throw new NumberFormatException("empty string is not a number");
/* 1546 */     char sign = str.charAt(0);
/* 1547 */     if ((sign == '+') || (sign == '-'))
/* 1548 */       throw new NumberFormatException("sign not allowed: " + str);
/* 1549 */     return Integer.parseInt(str);
/*      */   }
/*      */   
/*      */   private void parseByDayList(String str, List<ZWeekDayNum> list) {
/* 1553 */     for (String s : str.split("\\s*,\\s*")) {
/* 1554 */       ZWeekDayNum wdn = new ZWeekDayNum();
/*      */       
/* 1556 */       String dayStr = s;
/*      */       
/* 1558 */       if (s.length() > 2) {
/* 1559 */         String numStr = s.substring(0, s.length() - 2);
/* 1560 */         dayStr = dayStr.substring(s.length() - 2);
/* 1561 */         wdn.mOrdinal = parseSignedInt(numStr);
/*      */       }
/* 1563 */       wdn.mDay = ZWeekDay.valueOf(dayStr);
/*      */       
/* 1565 */       list.add(wdn);
/*      */     }
/*      */     
/*      */ 
/* 1569 */     Collections.sort(list, new ZRecur.ZWeekDayNum.DayOnlyComparator());
/*      */   }
/*      */   
/*      */   private void parseIntList(String str, List<Integer> list, int min, int max, boolean signed) {
/* 1573 */     for (String s : str.split("\\s*,\\s*"))
/*      */       try { int readInt;
/*      */         int readInt;
/* 1576 */         if (signed) {
/* 1577 */           readInt = parseSignedInt(s);
/*      */         } else
/* 1579 */           readInt = parseUnsignedInt(s);
/* 1580 */         if ((readInt >= min) && (readInt <= max)) {
/* 1581 */           list.add(Integer.valueOf(readInt));
/*      */         }
/*      */       } catch (Exception e) {
/* 1584 */         ZimbraLog.calendar.debug(new Formatter().format("Skipping unparsable Recur int list entry: \"%s\" in parameter list: \"%s\"", new Object[] { s, str }));
/*      */       }
/* 1586 */     Collections.sort(list);
/*      */   }
/*      */   
/*      */   private static class ExpansionLimits
/*      */   {
/*      */     public int maxInstances;
/*      */     public int maxDays;
/*      */     public int maxWeeks;
/*      */     public int maxMonths;
/*      */     public int maxYears;
/*      */     public int maxYearsOtherFreqs;
/*      */   }
/*      */ }


/* Location:              /home/mint/zimbrastore.jar!/com/zimbra/cs/mailbox/calendar/ZRecur.class
 * Java compiler version: 7 (51.0)
 * JD-Core Version:       0.7.1
 */